package br.com.skillocr.ocr;

import javax.ejb.Stateless;
import javax.jws.WebService;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.HashSet;
import java.util.Set;
import br.com.skillocr.redeneural.som.SelfOrganizingMap;
import br.com.skillocr.redeneural.som.TrainSelfOrganizingMap;
import br.com.skillocr.redeneural.som.NormalizeInput.NormalizationType;
import br.com.skillocr.redeneural.som.TrainSelfOrganizingMap.LearningMethod;

@Stateless
@WebService
public class SkillOCR implements SkillOCRIntf {
	static final int ALTURA_GRID = 7;
	static final int LARGURA_GRID = 7;
	static final double MAX_ERROR = 0.01;
	
	static SelfOrganizingMap redeLetras;
	
	static int quantidadeLetras;
	static boolean paradaTreino;
	
	static Set<Letras> listaLetras = new HashSet<Letras>();
	
	protected static void lerArquivo() {
		try {
			FileReader arquivo;
            BufferedReader bufferLeitura;
            
            arquivo = new FileReader(new File("c:/exemplo.txt"));
            bufferLeitura = new BufferedReader(arquivo);
            
            String linha;
            
            while ((linha = bufferLeitura.readLine()) != null) {
            	Letras letra = new Letras(linha.charAt(0),LARGURA_GRID,ALTURA_GRID);
            	quantidadeLetras++;
            	listaLetras.add(letra);
                int idx = 2;
                for (int y = 0; y < ALTURA_GRID; y++) {
                        for (int x = 0; x < LARGURA_GRID; x++) {
                                letra.setGrid(x, y, linha.charAt(idx++) == '1');
                        }
                }
            }
		} catch (final Exception e) {
			e.printStackTrace();
		}
	}
	
	protected static void treinarRede() {
		try {
			int neuroniosEntrada = ALTURA_GRID
									* LARGURA_GRID;
			int neuroniosSaida = quantidadeLetras;
			double[][] gridCompleto = new double[neuroniosSaida][neuroniosEntrada];
			
			int idx = 0;
			int idy = 0;
			
			for (Letras letra : listaLetras) {
                for (int y = 0; y < ALTURA_GRID; y++) {
                        for (int x = 0; x < LARGURA_GRID; x++) {
                        	gridCompleto[idx][idy++] = (letra.getGrid(x, y) ? .5 : -.5);
                        }
                }
                
                idx++;
                idy = 0;
			}
			
			redeLetras = new SelfOrganizingMap(neuroniosEntrada,neuroniosSaida,
                    							NormalizationType.MULTIPLICATIVE);
			TrainSelfOrganizingMap treino = new TrainSelfOrganizingMap(
                    redeLetras,gridCompleto,LearningMethod.SUBTRACTIVE,0.5);
			
			
            do {
            	treino.iteration();
            } while ((treino.getTotalError() > MAX_ERROR) && !paradaTreino);

            paradaTreino = true;

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	protected static char[] mapeiaNeuronios() {
		char[] letras = new char[quantidadeLetras];

        for (int i = 0; i < letras.length; i++) {
                letras[i] = '?';
        }
        
        for (Letras letra : listaLetras) {
        	double[] entrada = new double[ALTURA_GRID
  											*LARGURA_GRID];
            int idx = 0;
            
            for (int y = 0; y < ALTURA_GRID; y++) {
            	for (int x = 0; x < LARGURA_GRID; x++) {
            		entrada[idx++] = letra.getGrid(x, y) ? .5 : -.5;
            	}
            }

            final int best = redeLetras.winner(entrada);
            letras[best] = letra.getLetra();
        }
        return letras;
	}

	public String reconheceLetra(String mapaBits) {
    if(paradaTreino==false){
        lerArquivo();
        treinarRede();
    }
		
		double[] entrada = new double[ALTURA_GRID
										*LARGURA_GRID];
		
		for (int x = 0; x < ALTURA_GRID*LARGURA_GRID; x++) {
			entrada[x] = (mapaBits.charAt(x) == '1') ? .5 : -.5;
		}
		int vencedor = redeLetras.winner(entrada);
		char[] letras = mapeiaNeuronios();
		
		String letraVencedora = Character.toString(letras[vencedor]);
		
		return "Letra vencedora: "+letraVencedora;
	}
}
